home *** CD-ROM | disk | FTP | other *** search
/ IRIX 6.2 Applications 1996 May / SGI IRIX 6.2 Applications 1996 May.iso / dist / impr_dev.idb / usr / impressario / src / libspool / SLSysV.c.z / SLSysV.c
C/C++ Source or Header  |  1996-05-06  |  70KB  |  2,458 lines

  1. /**************************************************************************
  2.  *                                      *
  3.  *           Copyright (c)    1991 Silicon Graphics, Inc.          *
  4.  *            All Rights Reserved                    *
  5.  *                                      *
  6.  *       THIS    IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SGI          *
  7.  *                                      *
  8.  * The copyright notice above does not evidence any actual of intended      *
  9.  * publication of such source code, and is an unpublished work by Silicon *
  10.  * Graphics, Inc. This material contains CONFIDENTIAL INFORMATION that is *
  11.  * the property of Silicon Graphics, Inc. Any use, duplication or      *
  12.  * disclosure not specifically authorized by Silicon Graphics is strictly *
  13.  * prohibited.                                  *
  14.  *                                      *
  15.  * RESTRICTED RIGHTS LEGEND:                          *
  16.  *                                      *
  17.  * Use, duplication or disclosure by the Government is subject to      *
  18.  * restrictions as set forth in subdivision (c)(1)(ii) of the Rights in      *
  19.  * Technical Data and Computer Software clause at DFARS 52.227-7013,      *
  20.  * and/or in similar or successor clauses in the FAR, DOD or NASA FAR      *
  21.  * Supplement. Unpublished - rights reserved under the Copyright Laws of  *
  22.  * the United States. Contractor is SILICON GRAPHICS, INC., 2011 N.      *
  23.  * Shoreline Blvd., Mountain View, CA 94039-7311              *
  24.  **************************************************************************
  25.  *
  26.  * File: SLSysV.c
  27.  *
  28.  * Description: This file contains the System V spooling system specific
  29.  *    handling functions.
  30.  *
  31.  **************************************************************************/
  32.  
  33.  
  34. #ident "$Revision: 1.19 $"
  35.  
  36.  
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include <unistd.h>
  40. #include <limits.h>
  41. #include <dirent.h>
  42. #include <string.h>
  43. #include <ctype.h>
  44. #include <fcntl.h>
  45. #include <signal.h>
  46. #include <errno.h>
  47. #include <time.h>
  48. #include <pwd.h>
  49. #include <sys/types.h>
  50. #include <sys/stat.h>
  51. #include <sys/file.h>
  52. #include "spoolI.h"
  53.  
  54.  
  55. #ifndef sgi
  56. #define PATH_MAX    _POSIX_PATH_MAX
  57. #endif
  58.  
  59.  
  60. /* System V spooling directories and files */
  61.  
  62. #define SYSV_DEFAULT_FILE        "/var/spool/lp/default"
  63. #define SYSV_MEMBER_DIR            "/var/spool/lp/member"
  64. #define SYSV_CLASS_DIR            "/var/spool/lp/class"
  65. #define SYSV_INTERFACE_DIR        "/var/spool/lp/interface"
  66. #define SYSV_SPOOLER_FILE        ".glprc"
  67. #define SYSV_SETTINGS_DIR        "/var/spool/lp/settings"
  68. #define SYSV_DEFAULT_SETTINGS        "defaultSettings"
  69.  
  70. /* System V rc file switches */
  71.  
  72. #define SYSV_COPY_SWITCH             'c'
  73. #define SYSV_PRINTER_SWITCH          'd'
  74. #define SYSV_MAIL_SWITCH             'm'
  75. #define SYSV_MESS_SWITCH             'w'
  76. #define SYSV_NUMCOPIES_SWITCH        'n'
  77. #define SYSV_OPTIONS_SWITCH          'o'
  78. #define SYSV_SUPPRESS_SWITCH         's'
  79. #define SYSV_TITLE_SWITCH            't'
  80.  
  81. #define SYSV_MESS_OPTION             "-w"
  82. #define SYSV_OPTIONS_OPTION          "-o"
  83. #define SYSV_SUPPRESS_OPTION         "-s"
  84.  
  85. /* System V misc values */
  86.  
  87. #define SYSV_LOGMAX    15    /* Max chars in a logname according to lp.h */
  88.  
  89.  
  90. /* Interface file keyword parsing structure */
  91.  
  92. typedef struct {
  93.     char *key;            /* Keyword in interface script */
  94.     short len;            /* Number of characters in key */
  95.     char **pvar;        /* Pointer to string var in printer struct */
  96.     short found;        /* Indicates if keyword found */
  97. } KeywordStruct;
  98.  
  99. static KeywordStruct keywords[] = {
  100.     { "TYPE", 4, NULL, 0 },
  101.     { "NAME", 4, NULL, 0 },
  102.     { "HOSTNAME", 8, NULL, 0 },
  103.     { "HOSTPRINTER", 11, NULL, 0 },
  104.     { "NETTYPE", 7, NULL, 0 },
  105.     };
  106. static int num_keywords = sizeof(keywords) / sizeof(KeywordStruct);
  107.  
  108.  
  109. /* Union for spooler independent and spooler dependent settings structs */
  110.  
  111. typedef union {
  112.     SLSettingsStruct *generic;            /* Spooler independent */
  113.     SLSysVSpoolerOptionsStruct *specific;    /* Spooler specific */
  114. } SettingsUnion;
  115.  
  116. #define SYSV_GENERIC    0
  117. #define SYSV_SPECIFIC    1
  118.  
  119.  
  120. /* Print queue */
  121.  
  122. static SLQueueStruct *sysv_queue;        /* Job queue */
  123. static int num_sysv_queue;            /* Number of jobs in queue */
  124.  
  125.  
  126. /* Local functions */
  127.  
  128. static int get_printer_info(const char*, SLPrinterStruct*);
  129. static int get_class_member(const char*, char*);
  130. static void get_class_info(const char*, SLPrinterStruct*, SLPrinterStruct*);
  131. static void parse_interface(SLPrinterStruct*, FILE*);
  132. static SLPrinterStruct *find_printer(char*, SLPrinterStruct*, int);
  133. static char *get_def_pname(void);
  134. static void parse_queue(SLQueueStruct*, char*);
  135. static time_t parse_tstamp(const char*);
  136. static uid_t getlpuid(void);
  137. static void read_spooler_opts_file(SettingsUnion*, int);
  138. static char* read_printer_opts_file(const char*);
  139. static int write_spooler_opts_file(SLSysVSpoolerOptionsStruct*);
  140. static int write_printer_opts_file(const char*, char*, int);
  141. static void add_opts(char**, char*);
  142. static int sgi_get_queue(const SLPrinterStruct *printer_info, int queue_type,
  143.              SLQueueStruct *queuep[], int *num_queuep);
  144. static char *parse(char *string, char separator);
  145. static int jobs_equal(const SLPrinterStruct *printer_info,
  146.               SLQueueStruct *q1, SLQueueStruct *q2);
  147. static void sgi_parse_queue(SLQueueStruct *entry, char *line);
  148.  
  149.  
  150. /**************************************************************************
  151.  *
  152.  * Function: _SLSysVFindSpooler
  153.  *
  154.  * Description: Determines whether the System V print scheduler is running.
  155.  *
  156.  * Parameters: none
  157.  *
  158.  * Return: 1 if the scheduler is running, 0 otherwise.
  159.  *
  160.  **************************************************************************/
  161.  
  162. int _SLSysVFindSpooler(void)
  163. {
  164.     char cmd_buf[SL_BUFSIZ];
  165.  
  166.     /*
  167.      * Run "lpstat -r".  If the spooler is running, lpstat will print
  168.      * "scheduler is running".  Grep for the "is running" part.
  169.      */
  170.     (void)sprintf(cmd_buf, "%s -r", SL_CMD_LPSTAT);
  171.     if (_SLExec(NULL, cmd_buf, SL_FALSE, NULL) == 0
  172.     && _SLspooler_nout
  173.     && strstr(*_SLspooler_out_buf, "is running") != NULL) {
  174.     return 1;
  175.     }
  176.  
  177.     return 0;
  178. }
  179.  
  180.  
  181. /**************************************************************************
  182.  *
  183.  * Function: _SLSysVGetPrinterList
  184.  *
  185.  * Description: Provides a list of the printers recognized by the
  186.  *    System V spooling system. This function frees the old internal
  187.  *    printer list and allocates a new one. Because of this any pointer
  188.  *    the user may have from a previous call to this function is made
  189.  *    invalid. If a user wishes to preserve the old list, he must
  190.  *    copy it before calling this function.
  191.  *
  192.  * Parameters:
  193.  *    printersp (O) - set to a list of available printers
  194.  *    num_printersp (O) - number of available printers in list
  195.  *
  196.  * Return: 0 is execution succeeded. -1 and SLerrno is set if an execution
  197.  *    error has occurred.
  198.  *
  199.  **************************************************************************/
  200.  
  201. int _SLSysVGetPrinterList(SLPrinterStruct *printersp[], int *num_printersp)
  202. {
  203.     DIR *dptr;
  204.     struct dirent *dir_entry;
  205.     char buf[SL_SML_BUFSIZ], *cptr;
  206.     SLPrinterStruct info, *printer;
  207.     static SLPrinterStruct *sysv_printers = NULL;
  208.     static int num_sysv_printers = 0;
  209.  
  210.     /*
  211.      * Clear out and initialize the list of System V printers
  212.      */
  213.     _SLInitPlist(&sysv_printers, &num_sysv_printers);
  214.  
  215.     /*
  216.      * Read the printer member directory to find the known
  217.      * printers.
  218.      */
  219.     if ((dptr = opendir(SYSV_MEMBER_DIR)) == NULL) {
  220.         *num_printersp = num_sysv_printers;
  221.         *printersp = sysv_printers;
  222.     return SL_NOERROR;
  223.     }
  224.     while ((dir_entry = readdir(dptr)) != NULL) {
  225.     /*
  226.      * Skip the . entries
  227.      */
  228.     if (*dir_entry->d_name == '.')
  229.         continue;
  230.  
  231.     /*
  232.      * Get the printer info. If the printer is valid, add it
  233.      * to the list of printers
  234.      */
  235.     if (get_printer_info(dir_entry->d_name, &info) < 0)
  236.         continue;
  237.     _SLAddPrinter(&info, &sysv_printers, &num_sysv_printers);
  238.     }
  239.     (void)closedir(dptr);
  240.  
  241.     /*
  242.      * Check the class directory for any printer classes. A
  243.      * printer class will be treated as another printer. The
  244.      * class name will be the local_name and the data for
  245.      * the printer will come from the printer that is the
  246.      * first entry in the class file
  247.      */
  248.     if ((dptr = opendir(SYSV_CLASS_DIR)) != NULL) {
  249.         while ((dir_entry = readdir(dptr)) != NULL) {
  250.         if (*dir_entry->d_name == '.')
  251.             continue;
  252.  
  253.         /*
  254.          * Read the first line in the class file to determine
  255.          * which printer's characteristics this class should have.
  256.          * If there are any problems with the class skip it.
  257.          */
  258.         if (get_class_member(dir_entry->d_name, buf) < 0)
  259.         continue;
  260.  
  261.         /*
  262.          * Now locate the printer specified in the class file
  263.          */
  264.         if ((printer = find_printer(buf, sysv_printers, num_sysv_printers))
  265.                             == NULL)
  266.             continue;
  267.  
  268.         /*
  269.              * Add the printer class to the printer list
  270.               */
  271.         get_class_info(dir_entry->d_name, printer, &info);
  272.         _SLAddPrinter(&info, &sysv_printers, &num_sysv_printers);
  273.         }
  274.         (void)closedir(dptr);
  275.     }
  276.  
  277.     /*
  278.      * Finally, identify the default printer, if any
  279.      */
  280.     if ((cptr = get_def_pname()) != NULL) {
  281.         if ((printer = find_printer(cptr, sysv_printers, num_sysv_printers))
  282.                             != NULL) {
  283.         printer->is_def = 1;
  284.     }
  285.     }
  286.  
  287.     *num_printersp = num_sysv_printers;
  288.     *printersp = sysv_printers;
  289.  
  290.     return SL_NOERROR;
  291. }
  292.  
  293.  
  294. /**************************************************************************
  295.  *
  296.  * Function: _SLSysVGetPrinterInfo
  297.  *
  298.  * Description: Provides detailed information about the specified System
  299.  *    V printer. Each time this function is called the old contents of
  300.  *    the internal info structure become invalid. If the user wishes to
  301.  *    preserve the old info, a copy must be made before calling this
  302.  *    function.
  303.  *
  304.  * Parameters:
  305.  *      printer (I) - printer whose info is wanted. Public function sets
  306.  *              this to default printer name if user specified as
  307.  *              NULL.
  308.  *      printer_infop (O) - set to a printer information structure
  309.  *                      filled with information about the printer. Set
  310.  *                      to NULL if the specified printer does not exist.
  311.  *
  312.  * Return: 0 is execution succeeded. -1 and SLerrno is set if an execution
  313.  *      error has occurred. It is considered an error specifying a printer
  314.  *      that is not available to the spooler.
  315.  *
  316.  **************************************************************************/
  317.  
  318. int _SLSysVGetPrinterInfo(const char *printer, SLPrinterStruct **printer_infop)
  319. {
  320.     char buf[SL_SML_BUFSIZ], *dptr;
  321.     SLPrinterStruct info;
  322.     static SLPrinterStruct pinfo;
  323.  
  324.     /*
  325.      * First clear any storage that may have been allocated for the struct
  326.      */
  327.     _SLInitPentry(&pinfo);
  328.  
  329.     /*
  330.      * Next assume that this is a normal printer name and try to fill
  331.      * in information.
  332.      */
  333.     if (get_printer_info(printer, &pinfo) == 0) {
  334.     *printer_infop = &pinfo;
  335.     }
  336.     /*
  337.      * If not a valid printer name try it as a classname
  338.      */
  339.     else {
  340.     if (get_class_member(printer, buf) < 0)
  341.         RETURN_ERROR(SL_ERR_BAD_PRINTER_NAME);
  342.         if (get_printer_info(buf, &info) < 0)
  343.         RETURN_ERROR(SL_ERR_BAD_CLASS_MEMBER);
  344.     get_class_info(printer, &info, &pinfo);
  345.         *printer_infop = &pinfo;
  346.     }
  347.  
  348.     /*
  349.      * See if this is the default printer
  350.      */
  351.     if ((dptr = get_def_pname()) != NULL) {
  352.         if (!strcmp(dptr, pinfo.local_name))
  353.         pinfo.is_def = 1;
  354.     }
  355.  
  356.     return SL_NOERROR;
  357. }
  358.  
  359.  
  360. /**************************************************************************
  361.  *
  362.  * Function: _SLSysVGetDefPrinterName
  363.  *
  364.  * Description: Returns the default printer name recognized by the
  365.  *    System V spooling system.
  366.  *
  367.  * Parameters:
  368.  *    pnamep (O) - default printer or NULL if none selected.
  369.  *
  370.  * Return: 0 is execution succeeded. -1 and SLerrno is set if an execution
  371.  *    error has occurred. It is considered an error if there is no
  372.  *    default printer registered.
  373.  *
  374.  **************************************************************************/
  375.  
  376. int _SLSysVGetDefPrinterName(char **pnamep)
  377. {
  378.     if ((*pnamep = get_def_pname()) == NULL)
  379.     RETURN_ERROR(SL_ERR_NO_DEF_PRINTER);
  380.  
  381.     return SL_NOERROR;
  382. }
  383.  
  384.  
  385. /**************************************************************************
  386.  *
  387.  * Function: _SLSysVGetPrinterSettings
  388.  *
  389.  * Description: Reads the spooler and printer option settings that have
  390.  *      been saved.
  391.  *
  392.  *    Spooler options are stored in ~/SYSV_SPOOLER_FILE. Printer
  393.  *    specific options are stored in the directory defined by
  394.  *    SYSV_SETTINGS_DIR/[printer name]. The file is first looked
  395.  *    for under the username and if not found is then looked for
  396.  *    under the name defined by SYSV_DEFAULT_SETTINGS.
  397.  *
  398.  * Parameters:
  399.  *      printer (I) - printer whose settings are wanted. If NULL,
  400.  *                    the default printer is used. If the printer does
  401.  *              exist, default settings will be returned.
  402.  *      settingsp (O) - set to a printer settings structure
  403.  *                      filled with the currently saved settings.
  404.  *
  405.  * Return: 0 is execution succeeded. -1 and SLerrno is set if an execution
  406.  *      error has occurred.
  407.  *
  408.  **************************************************************************/
  409.  
  410. int _SLSysVGetPrinterSettings(const char *printer,
  411.                     SLSettingsStruct **settingsp)
  412. {
  413.     static SLSettingsStruct settings;
  414.     SettingsUnion sunion;
  415.     char *optr;
  416.  
  417.     /*
  418.      * First clear any storage associated with the old settings
  419.      * and initialize the structure to the default state.
  420.      */
  421.     settings.copy = 0;
  422.     settings.mail = 0;
  423.     if (settings.title) {
  424.     free((char*)settings.title);
  425.     settings.title = NULL;
  426.     }
  427.     if (settings.options) {
  428.     free((char*)settings.options);
  429.     settings.options = NULL;
  430.     }
  431.  
  432.     /*
  433.      * Read the spooler options file
  434.      */
  435.     sunion.generic = &settings;
  436.     read_spooler_opts_file(&sunion, SYSV_GENERIC);
  437.  
  438.     /*
  439.      * Read the printer option settings file
  440.      */
  441.     if ((optr = read_printer_opts_file(printer)) != NULL) {
  442.         char *opt_string = (char*)malloc((strlen(optr) + 10) * sizeof(char));
  443.         (void)sprintf(opt_string, "-o\"%s\"", optr);
  444.         add_opts(&settings.options, opt_string);
  445.         free((char*)opt_string);
  446.         free((char*)optr);
  447.     }
  448.  
  449.     /*
  450.      * Point the caller at the settings
  451.      */
  452.     *settingsp = &settings;
  453.  
  454.     return SL_NOERROR;
  455. }
  456.  
  457.  
  458. /**************************************************************************
  459.  *
  460.  * Function: _SLSysVGetSpoolerOptions
  461.  *
  462.  * Description: Reads the spooler options settings that have
  463.  *      been saved. The settings are returned in a System V
  464.  *    dependent structure.
  465.  *
  466.  *    Spooler options are stored in ~/SYSV_SPOOLER_FILE.
  467.  *
  468.  * Parameters:
  469.  *      spooler_optsp (O) - set to a spooler settings structure
  470.  *                      filled with the currently saved spooler options
  471.  *            or default values if no spooler options file
  472.  *            is found.
  473.  *
  474.  * Return: 0 is execution succeeded. -1 and SLerrno is set if an execution
  475.  *      error has occurred.
  476.  *
  477.  **************************************************************************/
  478.  
  479. int _SLSysVGetSpoolerOptions(SLSysVSpoolerOptionsStruct **spooler_optsp)
  480. {
  481.     static SLSysVSpoolerOptionsStruct spooler_opts;
  482.     SettingsUnion sunion;
  483.  
  484.     /*
  485.      * First clear any storage associated with the old settings
  486.      * and initialize the structure to the default state.
  487.      */
  488.     spooler_opts.copy = 0;
  489.     spooler_opts.mail = 0;
  490.     spooler_opts.message = 0;
  491.     spooler_opts.suppress_id = 0;
  492.     if (spooler_opts.title) {
  493.     free((char*)spooler_opts.title);
  494.     spooler_opts.title = NULL;
  495.     }
  496.  
  497.     /*
  498.      * Read the spooler options file
  499.      */
  500.     sunion.specific = &spooler_opts;
  501.     read_spooler_opts_file(&sunion, SYSV_SPECIFIC);
  502.  
  503.     /*
  504.      * Point the caller at the options
  505.      */
  506.     *spooler_optsp = &spooler_opts;
  507.  
  508.     return SL_NOERROR;
  509. }
  510.  
  511.  
  512. /**************************************************************************
  513.  *
  514.  * Function: _SLSysVGetPrinterOptions
  515.  *
  516.  * Description: Reads the printer specific option settings that have
  517.  *      been saved. The options are returned as a single string. This
  518.  *    is equivalent to the string specified using the "-o" switch to
  519.  *    lp.
  520.  *
  521.  *    Printer specific options are stored in the directory defined by
  522.  *    SYSV_SETTINGS_DIR/[printer name]. The file is first looked
  523.  *    for under the username and if not found is then looked for
  524.  *    under the name defined by SYSV_DEFAULT_SETTINGS.
  525.  *
  526.  * Parameters:
  527.  *      printer (I) - printer whose options are wanted.
  528.  *      printer_optsp (O) - set to point to s string of printer specific
  529.  *            options or NULL if no options can be found.
  530.  *
  531.  * Return: 0 is execution succeeded. -1 and SLerrno is set if an execution
  532.  *      error has occurred.
  533.  *
  534.  **************************************************************************/
  535.  
  536. int _SLSysVGetPrinterOptions(const char *printer, char **printer_optsp)
  537. {
  538.     static char *printer_opts;
  539.  
  540.     /*
  541.      * First clear any storage associated with the old options.
  542.      */
  543.     if (printer_opts) {
  544.     free((char*)printer_opts);
  545.     printer_opts = NULL;
  546.     }
  547.  
  548.     /*
  549.      * Read the printer specific options file
  550.      */
  551.     printer_opts = read_printer_opts_file(printer);
  552.  
  553.     /*
  554.      * Point the caller at the settings
  555.      */
  556.     *printer_optsp = printer_opts;
  557.  
  558.     return SL_NOERROR;
  559. }
  560.  
  561.  
  562. /**************************************************************************
  563.  *
  564.  * Function: _SLSysVSaveSpoolerOptions
  565.  *
  566.  * Description: Saves the spooler option settings for the System V spooler.
  567.  *
  568.  *    Spooler options are stored in ~/SYSV_SPOOLER_FILE.
  569.  *
  570.  * Parameters:
  571.  *      spooler_opts (I) - System V specific settings to be saved.
  572.  *
  573.  * Return: 0 is execution succeeded. -1 and SLerrno is set if an execution
  574.  *      error has occurred.
  575.  *
  576.  **************************************************************************/
  577.  
  578. int _SLSysVSaveSpoolerOptions(SLSysVSpoolerOptionsStruct *spooler_opts)
  579. {
  580.     if (write_spooler_opts_file(spooler_opts) < 0)
  581.     RETURN_ERROR(SL_ERR_SAVE_OPTIONS);
  582.  
  583.     return SL_NOERROR;
  584. }
  585.  
  586.  
  587. /**************************************************************************
  588.  *
  589.  * Function: _SLSysVSavePrinterOptions
  590.  *
  591.  * Description: Saves the printer specific option settings. 
  592.  *
  593.  *    Printer specific options are stored in the directory defined by
  594.  *    SYSV_SETTINGS_DIR/[printer name]. If location is set to
  595.  *    SL_SAVE_USER the file is written under the username. If location
  596.  *    is SL_SAVE_DEFAULT, the file is written with the name defined
  597.  *    by SYSV_DEFAULT_SETTINGS.
  598.  *
  599.  * Parameters:
  600.  *      printer (I) - printer whose options are to be saved.
  601.  *      printer_opts (I) - pritner specific options to be saved.
  602.  *    location (I) - Save settings for this user (SL_SAVE_USER) or
  603.  *            for all users (SL_SAVE_DEFAULT).
  604.  *
  605.  * Return: 0 is execution succeeded. -1 and SLerrno is set if an execution
  606.  *      error has occurred.
  607.  *
  608.  **************************************************************************/
  609.  
  610. int _SLSysVSavePrinterOptions(const char *printer,
  611.                 char *printer_opts, int location)
  612. {
  613.     /*
  614.      * Write the options file
  615.      */
  616.     if (write_printer_opts_file(printer, printer_opts, location) < 0)
  617.     RETURN_ERROR(SL_ERR_SAVE_OPTIONS);
  618.  
  619.     return SL_NOERROR;
  620. }
  621.  
  622.  
  623. /**************************************************************************
  624.  *
  625.  * Function: _SLSysVSubmitJob
  626.  *
  627.  * Description: Submits a job for printing using the System V spooler.
  628.  *
  629.  * Parameters:
  630.  *    job_source (I) - union describing the print job source (eg.
  631.  *        filename, fd, etc.)
  632.  *    printer (I) - printer on which to print job. Public function
  633.  *              sets this to the default printer name if user
  634.  *              specified this as NULL.
  635.  *    num_copies (I) - number of copies
  636.  *    copy (I) - Copy flag. If 1 then file is copied to spooling dir. If
  637.  *           0 a link is created.
  638.  *      mail (I) - Mail flag. If 1 then mail is sent on job print completion.
  639.  *           If 0, no mail is sent.
  640.  *    title (I) - title to appear on banner page.
  641.  *    options (I) - string of spooling system/printer specific options.
  642.  *              Set to NULL if none.
  643.  *    job_idp (O) - print job ID
  644.  *
  645.  * Return: 0 if no error. -1 and SLerrno set if error.
  646.  *
  647.  **************************************************************************/
  648.  
  649. int _SLSysVSubmitJob(SLJobSourceUnion *job_source, const char *printer,
  650.                 int num_copies, int copy, int mail,
  651.                 const char *title, const char *options,
  652.                 char **job_idp)
  653. {
  654.     char cmd_buf[SL_BUFSIZ], buf[SL_BUFSIZ];
  655.     char *id_ptr;
  656.     char *t_ptr;
  657.     char *b_ptr;
  658.  
  659.     /*
  660.      * Start filling the command buffer with parameters. Start
  661.      * with the printing command and the destination printer.  Command
  662.      * will looks something like:  
  663.      * /usr/bin/lp -d5L -c -t"a \' test" /etc/passwd 2>&1
  664.      */
  665.     (void)sprintf(cmd_buf, "%s -d%s", SL_CMD_LP, printer);
  666.     
  667.     /* Number of copies */
  668.     if (num_copies > 1) {
  669.         (void)sprintf(buf, " -n%d", num_copies);
  670.         (void)strcat(cmd_buf, buf);
  671.     }
  672.  
  673.     /* Copy file to spool dir */
  674.     if (copy)
  675.         (void)strcat(cmd_buf, " -c");
  676.  
  677.     /* Mail sent on completion */
  678.     if (mail)
  679.         (void)strcat(cmd_buf, " -m");
  680.  
  681.     /* Banner page title --  handle a char at a time to handle case of
  682.      * characters that the shell will interpret
  683.      */
  684.     if (title) {
  685.         for (t_ptr = (char *)title, b_ptr = buf; *t_ptr; t_ptr++) {
  686.            if ( !isalnum((int) *t_ptr) && !isspace((int) *t_ptr) ) {
  687.               *b_ptr++ = '\\';   /* Escape these */
  688.            }
  689.            *b_ptr++ = *t_ptr;
  690.            if ((b_ptr - buf) == SL_BUFSIZ-10) break; /* Stay in bounds */
  691.         }
  692.         *b_ptr = '\0'; 
  693.  
  694.     /* (void)sprintf(buf, " -t'%s'", title); */
  695.         (void)strcat(cmd_buf, " -t\"");
  696.     (void)strcat(cmd_buf, buf);
  697.         (void)strcat(cmd_buf, "\"");
  698.     }
  699.  
  700.     /* Printer/Spooler specific options */
  701.     if (options) {
  702.     (void)sprintf(buf, " %s", options);
  703.     (void)strcat(cmd_buf, buf);
  704.     }
  705.     
  706.     /* Add the file(s) to print, if appropriate */
  707.     if (job_source->type == SL_JOB_FILENAME) {
  708.         (void)sprintf(buf, " %s", job_source->filename_job.filename);
  709.         (void)strcat(cmd_buf, buf);
  710.     }
  711.  
  712.     /* Lastly add the sh stderr redirection */
  713.     (void)sprintf(buf, " %s", SL_SH_REDIRECT);
  714.     (void)strcat(cmd_buf, buf);
  715.  
  716.     /*
  717.      * Issue the command and if successful parse the output
  718.      * buffer for the job ID
  719.      */
  720.     if (_SLExec(job_source, cmd_buf, SL_FALSE, NULL) != 0) {
  721.     RETURN_ERROR(SL_ERR_SPOOLER_ERROR);
  722.     }
  723.     if (_SLspooler_nout) {
  724.     char *loc;
  725.  
  726.     (void)sprintf(cmd_buf, "%s-", printer);
  727.     if ((id_ptr = strstr(_SLspooler_out_buf[_SLspooler_nout-1], cmd_buf))
  728.                         != NULL) {
  729.         (void)strtok_r(id_ptr, " ", &loc);
  730.     }
  731.     *job_idp = id_ptr;
  732.     } else
  733.     *job_idp = NULL;
  734.  
  735.     return SL_NOERROR;
  736. }
  737.  
  738.  
  739. /**************************************************************************
  740.  *
  741.  * Function: _SLSysVCancelJob
  742.  *
  743.  * Description: Sends a cancel print job request to the System V spooling
  744.  *    system. Note that there is no confirmation that a print job has
  745.  *    actually been canceled.
  746.  *
  747.  * Parameters: 
  748.  *    job_id (I) - print job ID(s) of the job(s) that are to be canceled.
  749.  *    printer (I) - not used. Printer is determined from job ID.
  750.  *
  751.  * Return: 0 is execution succeeded. -1 and SLerrno is set if an execution
  752.  *    error has occurred.
  753.  *
  754.  **************************************************************************/
  755. /* ARGSUSED */
  756.  
  757. int _SLSysVCancelJob(const char *job_id, const char *printer)
  758. {
  759.     char cmd_buf[SL_BUFSIZ];
  760.  
  761.     /*
  762.      * Fill the command buffer with parameters
  763.      *        cancel + job ID(s) + sh output redirection
  764.      */
  765.     (void)sprintf(cmd_buf, "%s %s %s",
  766.                 SL_CMD_CANCEL,
  767.                 job_id,
  768.                 SL_SH_REDIRECT);
  769.  
  770.     /*
  771.      * Issue the command
  772.      */
  773.     if (_SLExec(NULL, cmd_buf, SL_FALSE, NULL) != 0)
  774.     RETURN_ERROR(SL_ERR_SPOOLER_ERROR);
  775.  
  776.     return SL_NOERROR;
  777. }
  778.  
  779.  
  780. /**************************************************************************
  781.  *
  782.  * Function: _SLSysVGetSpoolerState
  783.  *
  784.  * Description: Returns the state of the specified spooling function for
  785.  *    the System V spooling system.
  786.  *
  787.  * Parameters:
  788.  *    printer (I) - printer whose spooler state to query.
  789.  *    function (I) - spooling function whose state to query (one of
  790.  *                     SL_PRINTING or SL_QUEUEING).
  791.  *    statep (O) - state of the spooling function (one of SL_ENABLED or
  792.  *                   SL_DISABLED).
  793.  *
  794.  * Return: 0 is execution succeeded. -1 and SLerrno is set if an execution
  795.  *    error has occurred.
  796.  *
  797.  **************************************************************************/
  798.  
  799. int _SLSysVGetSpoolerState(const char *printer, int function, int *statep)
  800. {
  801.     char cmd_buf[SL_BUFSIZ];
  802.  
  803.     /*
  804.      * Fill the command buffer with parameters
  805.      *        lpstat + printing | queueing + printer + sh output redirection
  806.      */
  807.     (void)sprintf(cmd_buf, "%s -%c%s %s",
  808.                 SL_CMD_LPSTAT,
  809.                 (function == SL_PRINTING) ? 'p': 'a',
  810.                 printer,
  811.                 SL_SH_REDIRECT);
  812.  
  813.     /*
  814.      * Issue the command
  815.      */
  816.     if (_SLExec(NULL, cmd_buf, SL_FALSE, NULL) != 0)
  817.     RETURN_ERROR(SL_ERR_SPOOLER_ERROR);
  818.  
  819.     /*
  820.      * Parse out the state information
  821.      */
  822.     if (_SLspooler_nout) {
  823.         if (function == SL_PRINTING) {
  824.         if (strstr(*_SLspooler_out_buf, "disabled") != NULL)
  825.         *statep = SL_DISABLED;
  826.         else if (strstr(*_SLspooler_out_buf, "enabled") != NULL)
  827.         *statep = SL_ENABLED;
  828.         else {
  829.         _SLspooler_exit = 1;    /* Stupid System V returned 0 */
  830.         RETURN_ERROR(SL_ERR_SPOOLER_ERROR);
  831.         }
  832.         } else {    /* Queueing */
  833.         if (strstr(*_SLspooler_out_buf, "not accepting") != NULL)
  834.         *statep = SL_DISABLED;
  835.         else if (strstr(*_SLspooler_out_buf, "accepting") != NULL)
  836.         *statep = SL_ENABLED;
  837.         else {
  838.         _SLspooler_exit = 1;    /* Stupid System V returned 0 */
  839.         RETURN_ERROR(SL_ERR_SPOOLER_ERROR);
  840.         }
  841.         }
  842.     } else
  843.     RETURN_ERROR(SL_ERR_NO_STATE);
  844.  
  845.     return SL_NOERROR;
  846. }
  847.  
  848.  
  849. /**************************************************************************
  850.  *
  851.  * Function: _SLSysVSetSpoolerState
  852.  *
  853.  * Description: Sets the state of the specified spooling function for the
  854.  *    System V spooling system.
  855.  *
  856.  * Parameters:
  857.  *    printer (I) - printer whose spooler state to set.
  858.  *    function (I) - spooling function whose state to set (one of
  859.  *                   SL_PRINTING or SL_QUEUEING).
  860.  *    state (I) - state to set for the spooling function (one of
  861.  *                 SL_ENABLED or SL_DISABLED).
  862.  *
  863.  * Return: 0 is execution succeeded. -1 and SLerrno is set if an execution
  864.  *    error has occurred.
  865.  *
  866.  **************************************************************************/
  867.  
  868. int _SLSysVSetSpoolerState(const char *printer, int function, int state)
  869. {
  870.     char cmd_buf[SL_BUFSIZ], buf[SL_BUFSIZ];
  871.     uid_t my_id;
  872.  
  873.     /*
  874.      * Start filling the command buffer with parameters. Note
  875.      * that lp requires root or lp permission for enale/disable
  876.      * and for accept/reject. The System V spooling system in SGI
  877.      * Releases 4.0.1 and earlier allowed anyone to enable/disable.
  878.      * This has now been changed. Note also that for disable/enable
  879.      * I test your euid and for accept/reject I test uid. This is what
  880.      * the actual lp programs will test so I need to do the same so
  881.      * that you are not likely to pass my test and fail their's.
  882.      */
  883.     if (function == SL_PRINTING) {
  884.     if ((my_id = geteuid()) != 0 && my_id != getlpuid())
  885.         RETURN_ERROR(SL_ERR_PRIVILEGE);
  886.         (void)strcpy(cmd_buf, (state == SL_ENABLED) ? 
  887.                     SL_CMD_ENABLE: SL_CMD_DISABLE);
  888.     } else {    /* Queueing */
  889.     if ((my_id = getuid()) != 0 && my_id != getlpuid())
  890.         RETURN_ERROR(SL_ERR_PRIVILEGE);
  891.         (void)strcpy(cmd_buf, (state == SL_ENABLED) ? 
  892.                     SL_CMD_ACCEPT: SL_CMD_REJECT);
  893.     }
  894.  
  895.     /* Add the printer and sh output redirection */
  896.     (void)sprintf(buf, " %s %s", printer, SL_SH_REDIRECT);
  897.     (void)strcat(cmd_buf, buf);
  898.  
  899.     /*
  900.      * Issue the command
  901.      */
  902.     if (_SLExec(NULL, cmd_buf, SL_FALSE, NULL) != 0)
  903.     RETURN_ERROR(SL_ERR_SPOOLER_ERROR);
  904.  
  905.     /*
  906.      * Determine whether we really succeeded. System V is terrible
  907.      * at sending back error return codes if a command failed.
  908.      * The heuristic we use is if the first word on the first line
  909.      * of the returned string is the command name itself, we have failed.
  910.      * We worry about this only for disable/enable.
  911.      */
  912.     if (_SLspooler_nout && function == SL_PRINTING) {
  913.     (void)sprintf(cmd_buf, "%s", (state == SL_ENABLED) ?
  914.                 "enabled": "disabled");
  915.     if (strstr(*_SLspooler_out_buf, cmd_buf) == NULL) {
  916.         _SLspooler_exit = 1;    /* Stupid System V returned 0 */
  917.         RETURN_ERROR(SL_ERR_SPOOLER_ERROR);
  918.     }
  919.     }
  920.  
  921.     return SL_NOERROR;
  922. }
  923.  
  924.  
  925. /**************************************************************************
  926.  *
  927.  * Function: _SLSysVGetQueue
  928.  *
  929.  * Description: Returns the job queue for the specified printer under
  930.  *    the System V spooling system.
  931.  *
  932.  * Parameters:
  933.  *    printer_info (I) - printer structure. Cannot be NULL.
  934.  *    queue_type (I) - type of print queue to obtain (ie. local, remote
  935.  *                or merged). The value of this parameter is
  936.  *                ignored for local printers.
  937.  *    queuep (O) - print queue entries.
  938.  *    num_queuep (O) - number of entries in the queue.
  939.  *
  940.  * Return: 0 is execution succeeded. -1 and SLerrno is set if an execution
  941.  *    error has occurred.
  942.  *
  943.  **************************************************************************/
  944.  
  945. int _SLSysVGetQueue(const SLPrinterStruct *printer_info, int queue_type,
  946.                 SLQueueStruct *queuep[], int *num_queuep)
  947. {
  948.     char cmd_buf[SL_BUFSIZ];
  949.     int i, start_ind, timeout;
  950.     SLQueueStruct *qentry, *qptr, temp_entry;
  951.  
  952.     /*
  953.      * Clear out and initialize the System V queue
  954.      */
  955.     _SLInitQueue(&sysv_queue, &num_sysv_queue);
  956.  
  957.     /*
  958.      * If the new stuff is installed, use it.
  959.      */
  960.     if (access("/usr/lib/liblp.so", F_OK) == 0) {
  961.     return sgi_get_queue(printer_info, queue_type, queuep, num_queuep);
  962.     }    
  963.  
  964.     /*
  965.      * First get the remote queue if this is a remote printer and we
  966.      * have not specified local queue explicitly
  967.      */
  968.     if (printer_info->is_networked && queue_type != SL_QUEUE_LOCAL) {
  969.  
  970.     /*
  971.      * Form the remote command
  972.      */
  973.     (void)sprintf(cmd_buf,
  974.         "%s %s -n -l lp '%s -c \"%s %s %s -o%s %s\"'",
  975.             SL_CMD_RSH, printer_info->remote_host,
  976.             SL_CMD_SH_NAME, SL_LANG, SL_MSGFORMAT, SL_CMD_LPSTAT,
  977.             printer_info->remote_name, SL_SH_REDIRECT);
  978.  
  979.         /*
  980.          * Issue the remote command. Notice that we are issuing the
  981.      * command with a timeout. This is because we go over the
  982.      * net with rsh to get the remote queue. All kinds of nasty
  983.      * things can happen to trip us up, so we make sure that
  984.      * no matter what happens we will return from this call.
  985.          */
  986.         if ((_SLExec(NULL, cmd_buf, SL_TRUE, &timeout) != 0) ||
  987.                         (timeout == SL_TRUE))
  988.         RETURN_ERROR(SL_ERR_REMOTE);
  989.     if (_SLspooler_nout) {
  990.         (void)sprintf(cmd_buf, "%s:", SL_CMD_LPSTAT_NAME);
  991.         if (strstr(*_SLspooler_out_buf, cmd_buf)) {
  992.         _SLspooler_exit = 1;        /* System V forgets */
  993.         RETURN_ERROR(SL_ERR_SPOOLER_ERROR);
  994.         }
  995.     }
  996.  
  997.     /*
  998.      * Parse the command output to form the remote portion 
  999.      * of the queue
  1000.      */
  1001.     for (i = 0; i < _SLspooler_nout; i++) {
  1002.         qentry = _SLAddQueue(&sysv_queue, &num_sysv_queue);
  1003.         parse_queue(qentry, _SLspooler_out_buf[i]);
  1004.         qentry->is_local = 0;
  1005.     }
  1006.     }
  1007.  
  1008.     /*
  1009.      * Now get the local queue if not networked or if want merged or
  1010.      * local queue for remote printer.
  1011.      */
  1012.     if (!printer_info->is_networked || queue_type != SL_QUEUE_REMOTE) {
  1013.         (void)sprintf(cmd_buf, "%s -o%s %s", SL_CMD_LPSTAT,
  1014.                 printer_info->local_name, SL_SH_REDIRECT);
  1015.         if (_SLExec(NULL, cmd_buf, SL_FALSE, NULL) != 0)
  1016.             RETURN_ERROR(SL_ERR_SPOOLER_ERROR);
  1017.         if (_SLspooler_nout) {
  1018.         (void)sprintf(cmd_buf, "%s:", SL_CMD_LPSTAT_NAME);
  1019.         if (strstr(*_SLspooler_out_buf, cmd_buf)) {
  1020.             _SLspooler_exit = 1;        /* System V forgets */
  1021.             RETURN_ERROR(SL_ERR_SPOOLER_ERROR);
  1022.         }
  1023.     }
  1024.     }
  1025.  
  1026.     /*
  1027.      * Merge the local queue with the remote queue, if any
  1028.      * A merge is done by matching the first job on the local queue
  1029.      * to the last job on the remote queue that has the same owner and
  1030.      * same size. This is really piss poor, but given the general brain
  1031.      * death in the architecture of these spooling systems, it is the
  1032.      * best we can do.
  1033.      */
  1034.     start_ind = 0;
  1035.     if (printer_info->is_networked && queue_type == SL_QUEUE_MERGED) {
  1036.     if (_SLspooler_nout) {
  1037.  
  1038.         /*
  1039.          * Parse the first entry in the local queue
  1040.          */
  1041.         parse_queue(&temp_entry, *_SLspooler_out_buf);
  1042.         temp_entry.is_local = 1;
  1043.  
  1044.         /*
  1045.          * Compare it against the remote queue starting with the
  1046.          * last entry
  1047.          */
  1048.         for (i = 0, qptr = &sysv_queue[num_sysv_queue-1];
  1049.                 i < num_sysv_queue; i++, qptr--) {
  1050.  
  1051.         /*
  1052.          * Two entries are considered identical if the owner and
  1053.          * size are the same.
  1054.          */
  1055.         if ((qptr->username && temp_entry.username) &&
  1056.             (!strcmp(qptr->username, temp_entry.username)) &&
  1057.             (qptr->size == temp_entry.size)) {
  1058.  
  1059.             /*
  1060.              * Free the remote entry and replace it with the
  1061.              * local entry
  1062.              */
  1063.             _SLFreeQueueEntry(qptr);
  1064.             *qptr = temp_entry;
  1065.             start_ind = 1;
  1066.             break;
  1067.         }
  1068.         }
  1069.  
  1070.         /*
  1071.          * If first local entry not found on remote queue
  1072.          * free the storage for the first local entry
  1073.          */
  1074.         if (start_ind == 0)
  1075.         _SLFreeQueueEntry(&temp_entry);
  1076.     }
  1077.     }
  1078.  
  1079.     /*
  1080.      * Parse the remaining command output to form the local
  1081.      * queue portion of the queue
  1082.      */
  1083.     if (!printer_info->is_networked || queue_type != SL_QUEUE_REMOTE) {
  1084.         for (i = start_ind; i < _SLspooler_nout; i++) {
  1085.         qentry = _SLAddQueue(&sysv_queue, &num_sysv_queue);
  1086.         parse_queue(qentry, _SLspooler_out_buf[i]);
  1087.         qentry->is_local = 1;
  1088.         }
  1089.     }
  1090.  
  1091.     *num_queuep = num_sysv_queue;
  1092.     *queuep = sysv_queue;
  1093.  
  1094.     return SL_NOERROR;
  1095. }
  1096.  
  1097.  
  1098. #ifdef _SL_FASTPATH
  1099. /**************************************************************************
  1100.  *
  1101.  * Function: _SLSysVSupportsFastJob
  1102.  *
  1103.  * Description:
  1104.  *      Find out whether a printer supports fast print jobs
  1105.  *
  1106.  * Parameters:
  1107.  *      printer  printer to find out if supports fast jobs
  1108.  *
  1109.  * Return: non-zero if fast job supported, 0 otherwise
  1110.  *
  1111.  **************************************************************************/
  1112.  
  1113. int _SLSysVSupportsFastJob(const char *printer)
  1114. {
  1115.     int answer = SL_FALSE;
  1116.     char line[SL_SML_BUFSIZ], model[SL_SML_BUFSIZ], *pr;
  1117.     FILE *fp;
  1118.     SLPrinterStruct *p;
  1119.     static char *level2 = "LEVEL=2";
  1120.  
  1121.     if (!printer) {
  1122.     if (SLGetDefPrinterName(&pr) < 0) {
  1123.         return SL_FALSE;
  1124.     }
  1125.     printer = pr;
  1126.     }
  1127.  
  1128.     if (SLGetPrinterInfo(printer, &p) < 0) {
  1129.     return SL_FALSE;
  1130.     }
  1131.  
  1132.     if (p->dev) {
  1133.     (void)sprintf(model, "%s/%s", SYSV_INTERFACE_DIR, printer);
  1134.     fp = fopen(model, "r");
  1135.  
  1136.     if (fp) {
  1137.         while (fgets(line, sizeof(line), fp) != NULL) {
  1138.         if (strstr(line, level2)) {
  1139.             answer = SL_TRUE;
  1140.             break;
  1141.         }
  1142.         }
  1143.         (void)fclose(fp);
  1144.     }
  1145.     } else {
  1146.     /*
  1147.      * BLECH!!!!!
  1148.      */
  1149.     (void)sprintf(line,
  1150.         "/usr/bsd/rsh %s -n -l lp grep %s %s/%s %s",
  1151.         p->remote_host, level2, SYSV_INTERFACE_DIR,
  1152.         p->remote_name, SL_SH_REDIRECT);
  1153.     answer = _SLExec(NULL, line, SL_TRUE, NULL);
  1154.     }
  1155.     
  1156.     return answer;
  1157. }
  1158. #endif /* _SL_FASTPATH */
  1159.  
  1160.  
  1161. /**************************************************************************
  1162.  *
  1163.  * Function: _SLSysVFindUserName
  1164.  *
  1165.  * Description: Determines the user name in the same manner as the System V
  1166.  *      spooling system. This code is taken from getname.c in
  1167.  *    usr/src/cmd/lp.
  1168.  *
  1169.  * Parameters: none
  1170.  *
  1171.  * Return: Pointer to user name. The storage for username is static and
  1172.  *      the returned value should be copied if it is not going to be
  1173.  *      used immediately after the call.
  1174.  *
  1175.  **************************************************************************/
  1176.  
  1177. char* _SLSysVFindUserName(void)
  1178. {
  1179.     uid_t uid;
  1180.     struct passwd *p;
  1181.     static char logname[SYSV_LOGMAX + 1];
  1182.     char *l;
  1183.  
  1184.     uid = getuid();
  1185.     setpwent();
  1186.     l = getenv("LOGNAME");
  1187.     if ((l == NULL) ||
  1188. #ifdef sgi
  1189.            /* Let the administrator override the user's name to make
  1190.           remote printing work better. */
  1191.         ((p = getpwnam(l)) == NULL || p->pw_uid != uid) &&
  1192.             !(uid == 0 || (((p = getpwnam("lp")) != NULL)  &&
  1193.         p->pw_uid == uid)))
  1194. #else
  1195.         (p = getpwnam(l)) == NULL || p -> pw_uid != uid)
  1196. #endif
  1197.     if ((p = getpwuid(uid)) != NULL)
  1198.         l = p->pw_name;
  1199.         else
  1200.             l = NULL;
  1201.  
  1202.     if (l != NULL) {
  1203.         (void)strncpy(logname, l, SYSV_LOGMAX);
  1204.         logname[SYSV_LOGMAX] = '\0';
  1205.     }
  1206.     else
  1207.         (void)sprintf(logname, "%ld", uid);
  1208.     endpwent();
  1209.  
  1210.     return logname;
  1211. }
  1212.  
  1213.  
  1214. /*
  1215.  ==========================================================================
  1216.              LOCAL FUNCTIONS
  1217.  ==========================================================================
  1218. */
  1219.  
  1220.  
  1221. /**************************************************************************
  1222.  *
  1223.  * Function: get_printer_info
  1224.  *
  1225.  * Description: Fills the specified print information structure with
  1226.  *    detailed information about the speicified printer.
  1227.  *
  1228.  * Parameters: 
  1229.  *    pname (I) - printer name
  1230.  *    info (O) - printer info structure to be filled
  1231.  *
  1232.  * Return: 0 if the printer is valid or -1 if the printer is not
  1233.  *    valid.
  1234.  *
  1235.  **************************************************************************/
  1236.  
  1237. static int get_printer_info(const char *pname, SLPrinterStruct *info)
  1238. {
  1239.     FILE *member_fptr, *inter_fptr;
  1240.     char buf[SL_SML_BUFSIZ];
  1241.  
  1242.     /*
  1243.      * Attempt to open the member and interface files.
  1244.      * If we have trouble indicate that the printer is invalid
  1245.      */
  1246.     (void)sprintf(buf, "%s/%s", SYSV_MEMBER_DIR, pname);
  1247.     if ((member_fptr = fopen(buf, "r")) == NULL)
  1248.         return -1;
  1249.     (void)sprintf(buf, "%s/%s", SYSV_INTERFACE_DIR, pname);
  1250.     if ((inter_fptr = fopen(buf, "r")) == NULL) {
  1251.         (void)fclose(member_fptr);
  1252.         return -1;
  1253.     }
  1254.  
  1255.     /*
  1256.      * Read the member file to determine what device the printer
  1257.      * is connected to and whether it is networked
  1258.      */
  1259.     if (fgets(buf, SL_SML_BUFSIZ, member_fptr) == NULL) {
  1260.         (void)fclose(member_fptr);
  1261.         (void)fclose(inter_fptr);
  1262.         return -1;
  1263.     }
  1264.     buf[strlen(buf) - 1] = '\0';
  1265.     info->local_name = strdup(SL_CHAR_CAST(pname));
  1266.     if (strcmp(buf, "/dev/null")) {
  1267.     info->dev = strdup(buf);
  1268.     info->is_networked = 0;
  1269.     } else {
  1270.     info->dev = NULL;
  1271.     info->is_networked = 1;
  1272.     }
  1273.     info->is_def = 0;
  1274.     info->is_class = 0;
  1275.  
  1276.     /*
  1277.      * Next parse the interface script files for each printer to
  1278.      * determine more details about the printers
  1279.      */
  1280.     parse_interface(info, inter_fptr);
  1281.  
  1282.     /*
  1283.      * Close the open files
  1284.      */
  1285.     (void)fclose(member_fptr);
  1286.     (void)fclose(inter_fptr);
  1287.  
  1288.     return 0;
  1289. }
  1290.  
  1291.  
  1292. /**************************************************************************
  1293.  *
  1294.  * Function: get_class_member
  1295.  *
  1296.  * Description: Provides the first member printer name from the specified
  1297.  *    printer class.
  1298.  *
  1299.  * Parameters: 
  1300.  *    cname (I) - printer class name
  1301.  *    pname (O) - first member printer name. Should be dimensioned to
  1302.  *            SL_SML_BUFSIZ.
  1303.  *
  1304.  * Return: 0 if class is valid, -1 if not a valid class name.
  1305.  *
  1306.  **************************************************************************/
  1307.  
  1308. static int get_class_member(const char *cname, char *pname)
  1309. {
  1310.     FILE *class_fptr;
  1311.     char buf[SL_SML_BUFSIZ];
  1312.  
  1313.     (void)sprintf(buf, "%s/%s", SYSV_CLASS_DIR, cname);
  1314.     if ((class_fptr = fopen(buf, "r")) == NULL)
  1315.         return -1;
  1316.     if (fgets(pname, SL_SML_BUFSIZ, class_fptr) == NULL)
  1317.         return -1;
  1318.     (void)fclose(class_fptr);
  1319.     pname[strlen(pname) - 1] = '\0';
  1320.  
  1321.     return 0;
  1322. }
  1323.  
  1324.  
  1325. /**************************************************************************
  1326.  *
  1327.  * Function: get_class_info
  1328.  *
  1329.  * Description: Copies the printer class information from the specified
  1330.  *    printer information structure.
  1331.  *
  1332.  * Parameters: 
  1333.  *    cname (I) - printer class name
  1334.  *    pinfo (I) - member printer information structure
  1335.  *    cinfo (O) - class information copied from pinfo
  1336.  *
  1337.  * Return: none
  1338.  *
  1339.  **************************************************************************/
  1340.  
  1341. static void get_class_info(const char *cname, SLPrinterStruct *pinfo,
  1342.                 SLPrinterStruct *cinfo)
  1343. {
  1344.     cinfo->local_name = strdup(SL_CHAR_CAST(cname));
  1345.     cinfo->formal_name = (pinfo->formal_name) ?
  1346.                 strdup(pinfo->formal_name): NULL;
  1347.     cinfo->type = (pinfo->type) ?
  1348.                 strdup(pinfo->type): NULL;
  1349.     cinfo->is_networked = pinfo->is_networked;
  1350.     cinfo->is_def = 0;
  1351.     cinfo->is_class = 1;
  1352.     cinfo->remote_host = (pinfo->remote_host) ?
  1353.                 strdup(pinfo->remote_host): NULL;
  1354.     cinfo->remote_name = (pinfo->remote_name) ?
  1355.                 strdup(pinfo->remote_name): NULL;
  1356.     cinfo->dev = (pinfo->dev) ? strdup(pinfo->dev): NULL;
  1357. }
  1358.  
  1359.  
  1360. /**************************************************************************
  1361.  *
  1362.  * Function: parse_interface
  1363.  *
  1364.  * Description: Parses the specified printer's interface script file
  1365.  *    to determine information about the printer. The keywords should
  1366.  *    appear in the interface script with the following syntax:
  1367.  *
  1368.  *    [whitespace]keyword[whitespace]=[whitespace]["]value["]
  1369.  *
  1370.  *    where items in brackets are optional.
  1371.  *
  1372.  * Parameters: 
  1373.  *    printer (I) - printer structure
  1374.  *    fptr (I) - pointer to the opened interface script file
  1375.  *
  1376.  * Return: none
  1377.  *
  1378.  **************************************************************************/
  1379.  
  1380. static void parse_interface(SLPrinterStruct *printer, FILE *fptr)
  1381. {
  1382.     char buf[SL_SML_BUFSIZ], *sptr, *kptr;
  1383.     register int i, len;
  1384.  
  1385.     /*
  1386.      * Initialize all info strings
  1387.      */
  1388.     printer->type = NULL;
  1389.     printer->formal_name = NULL;
  1390.     printer->remote_host = NULL;
  1391.     printer->remote_name = NULL;
  1392.     printer->network_type = NULL;
  1393.     keywords[0].pvar = &printer->type;
  1394.     keywords[1].pvar = &printer->formal_name;
  1395.     keywords[2].pvar = &printer->remote_host;
  1396.     keywords[3].pvar = &printer->remote_name;
  1397.     keywords[4].pvar = &printer->network_type;
  1398.  
  1399.     /*
  1400.      * Mark all keywords as not found
  1401.      */
  1402.     for (i = 0; i < num_keywords; i++)
  1403.         keywords[i].found = 0;
  1404.  
  1405.     /*
  1406.      * Parse the interface script
  1407.      */
  1408.     while (fgets(buf, SL_SML_BUFSIZ, fptr)) {
  1409.     /*
  1410.      * Strip off trailing newline and any " character at the end
  1411.      * We also handle the case where the '"' is followed by
  1412.      * whitespace before the newline.
  1413.      */
  1414.     len = strlen(buf);
  1415.     buf[--len] = '\0';
  1416.     for (i = len - 1; i >= 0; i--) {
  1417.         if (buf[i] == ' ')
  1418.         continue;
  1419.         else if (buf[i] == '"') {
  1420.             buf[i] = '\0';
  1421.         break;
  1422.         } else
  1423.         break;
  1424.     }
  1425.  
  1426.     /*
  1427.      * Skip any leading white space
  1428.      */
  1429.     if ((sptr = _SLSkipSpace(buf)) == NULL)
  1430.         continue;
  1431.  
  1432.     /*
  1433.      * Skip comment lines
  1434.      */
  1435.     if (*sptr == '#')
  1436.         continue;
  1437.  
  1438.     /*
  1439.      * Look for a keyword
  1440.      */
  1441.     for (i = 0; i < num_keywords; i++) {
  1442.         if (keywords[i].found)
  1443.         continue;
  1444.         if ((kptr = strstr(sptr, keywords[i].key)) == NULL)
  1445.         continue;
  1446.         if (kptr != buf && isalpha(kptr[-1]))
  1447.             continue;
  1448.         if ((kptr = _SLSkipSpace(kptr + keywords[i].len)) == NULL)
  1449.         continue;
  1450.         if (*kptr != '=')
  1451.         continue;
  1452.         if ((kptr = _SLSkipSpace(kptr + 1)) == NULL)
  1453.         continue;
  1454.         if (*kptr == '"')
  1455.         kptr++;
  1456.         *keywords[i].pvar = strdup(kptr);
  1457.         keywords[i].found = 1;
  1458.         break;
  1459.     }
  1460.  
  1461.     /*
  1462.      * If all the needed info has been obtained stop reading
  1463.      * the script file
  1464.      */
  1465.     if (printer->type && printer->formal_name) {
  1466.         if (printer->is_networked) {
  1467.         if (printer->remote_host && printer->remote_name)
  1468.             break;
  1469.         } else
  1470.         break;
  1471.     }
  1472.     }
  1473.  
  1474.     /*
  1475.      * oldsgi is the backwards compatible interface.
  1476.      */
  1477.     if (printer->is_networked && !printer->network_type) {
  1478.     printer->network_type = strdup("oldsgi");
  1479.     }
  1480.  
  1481.     /*
  1482.      * Complete incomplete info items
  1483.      */
  1484.     if (!printer->type)
  1485.     printer->type = strdup("Unknown");
  1486.     if (!printer->formal_name)
  1487.     printer->formal_name = strdup(printer->type);
  1488. }
  1489.  
  1490.  
  1491. /**************************************************************************
  1492.  *
  1493.  * Function: find_printer
  1494.  *
  1495.  * Description: Performs a linear search of the printer list looking
  1496.  *    for the specified printer. The key is the local_name.
  1497.  *
  1498.  * Parameters: 
  1499.  *    pname (I) - printer name to search for.
  1500.  *    plist (I) - list of available printers
  1501.  *    num_plist (I) - number of printers in the list
  1502.  *
  1503.  * Return: Returns a pointer to the printer structure if the printer was
  1504.  *    found in the printer list. Otherwise, NULL is returned.
  1505.  *
  1506.  **************************************************************************/
  1507.  
  1508. static SLPrinterStruct *find_printer(char *pname, SLPrinterStruct *plist,
  1509.                     int num_plist)
  1510. {
  1511.     SLPrinterStruct *ptr = NULL;
  1512.     register int i;
  1513.  
  1514.     for (i = 0 ; i < num_plist; i++) {
  1515.     if (!strcmp(plist[i].local_name, pname)) {
  1516.         ptr = &plist[i];
  1517.         break;
  1518.     }
  1519.     }
  1520.  
  1521.     return ptr;
  1522. }
  1523.  
  1524.  
  1525. /**************************************************************************
  1526.  *
  1527.  * Function: get_def_pname
  1528.  *
  1529.  * Description: Gets the default printer name if any.
  1530.  *
  1531.  * Parameters: none
  1532.  *
  1533.  * Return: Returns a the default printer name or NULL if no default
  1534.  *    printer is registered.
  1535.  *
  1536.  **************************************************************************/
  1537.  
  1538. static char *get_def_pname(void)
  1539. {
  1540.     FILE *fptr;
  1541.     char *cptr = NULL;
  1542.     static char buf[SL_SML_BUFSIZ];
  1543.  
  1544.     /*
  1545.      * Get the LPDEST environment variable setting, if any
  1546.      * otherwise read the system default file for a default printer,
  1547.      * if such a file exists
  1548.      */
  1549.     if ((cptr = getenv("LPDEST")) == NULL) {
  1550.         if ((fptr = fopen(SYSV_DEFAULT_FILE, "r")) != NULL) {
  1551.             if ((cptr = fgets(buf, SL_SML_BUFSIZ, fptr)) != NULL)
  1552.                 buf[strlen(buf) - 1] = '\0';
  1553.         (void)fclose(fptr);
  1554.     }
  1555.     }
  1556.  
  1557.     /*
  1558.      * If no def printer make sure pointer is NULL
  1559.      */
  1560.     if (cptr && *cptr == '\0')
  1561.         cptr = NULL;
  1562.  
  1563.     return cptr;
  1564. }
  1565.  
  1566.  
  1567. /**************************************************************************
  1568.  *
  1569.  * Function: parse_queue
  1570.  *
  1571.  * Description: Parses an lpstat queue output string and places the
  1572.  *    appropriate info in the specified queue structure.
  1573.  *
  1574.  * Parameters: 
  1575.  *    entry (O) - queue structure to be filled
  1576.  *    line (I) - lpstat output line to parse
  1577.  *
  1578.  * Return: none
  1579.  *
  1580.  **************************************************************************/
  1581.  
  1582. static void parse_queue(SLQueueStruct *entry, char *line)
  1583. {
  1584.     char *sptr, *dline, *tstamp = NULL;
  1585.     char *loc;
  1586.  
  1587.     /*
  1588.      * Initialize all fields in case not everything gets filled
  1589.      */
  1590.     entry->job_id = entry->username = NULL;
  1591.     entry->size = entry->time_stamp = 0;
  1592.     entry->title = NULL;
  1593.  
  1594.     dline = strdup(line);
  1595.     if ((sptr = strtok_r(dline, " ", &loc)) != NULL) {
  1596.         entry->job_id = strdup(sptr);
  1597.         if ((sptr = strtok_r(NULL, " ", &loc)) != NULL) {
  1598.             entry->username = strdup(sptr);
  1599.             if ((sptr = strtok_r(NULL, " ", &loc)) != NULL) {
  1600.             entry->size = atoi(sptr);
  1601.         if ((tstamp = strtok_r(NULL, " ", &loc)) != NULL)
  1602.             tstamp[strlen(tstamp)] = ' ';
  1603.         }
  1604.     }
  1605.     }
  1606.     entry->time_stamp = parse_tstamp(tstamp);
  1607.     free((char*)dline);
  1608. }
  1609.  
  1610.  
  1611. /**************************************************************************
  1612.  *
  1613.  * Function: parse_tstamp
  1614.  *
  1615.  * Description: Takes a standard time string as returned by ctime and
  1616.  *    parses it into a valid tm struct to send to mktime. We do this
  1617.  *    so that when we get a time string from say lpstat for a queue
  1618.  *    entry we can put it in our struct as a time_t number. Having the
  1619.  *    time stamp represented as a number if easier to work with when
  1620.  *    comparing times.
  1621.  *
  1622.  * Parameters: 
  1623.  *    time_stamp (I) - The ctime format time stamp string. The function
  1624.  *            works with whatever it is given as long as it follows
  1625.  *            the ctime format. For fields that are empty the 
  1626.  *            functions tries to put in "reasonable" defaults.
  1627.  *            Leaving to much out will lead to unreasonable
  1628.  *            results.
  1629.  *
  1630.  * Return: The time in seconds since the epoch. This is the value that
  1631.  *    would be reported by time(2).
  1632.  *
  1633.  **************************************************************************/
  1634.  
  1635. #define TIME_SIZE    26
  1636.  
  1637. static time_t parse_tstamp(const char *time_stamp)
  1638. {
  1639.     static const char *days = "SunMonTueWedThuFriSat";
  1640.     static const char *months = "JanFebMarAprMayJunJulAugSepOctNovDec";
  1641.     char buf[TIME_SIZE], *sptr, *str, *jtime = NULL;
  1642.     char *loc;
  1643.     time_t tval;
  1644.     struct tm *tmp, cur_tm, new_tm;
  1645.  
  1646.     /*
  1647.      * First check that we have anything to parse
  1648.      */
  1649.     if (!time_stamp || *time_stamp == '\0')
  1650.     return (time_t)0;
  1651.     (void)strncpy(buf, time_stamp, TIME_SIZE);
  1652.     buf[TIME_SIZE - 1] = '\0';
  1653.     if ((str = strtok_r(buf, " ", &loc)) == NULL)
  1654.     return (time_t)0;
  1655.  
  1656.     /*
  1657.      * Get the epoch time and the current time. The epoch is
  1658.      * 00:00:00 GMT Jan 1, 1970. We initialize the new time value
  1659.      * to the epoch and use the current time for daylight savings time
  1660.      * info and the current year.
  1661.      */
  1662.     tval = (time_t)0;
  1663.     tmp = localtime(&tval);
  1664.     new_tm = *tmp;
  1665.     tval = time((time_t*)NULL);
  1666.     tmp = localtime(&tval);
  1667.     cur_tm = *tmp;
  1668.     new_tm.tm_isdst = cur_tm.tm_isdst;
  1669.  
  1670.     /*
  1671.      * If the time stamp starts with a day name, ignore it
  1672.      */
  1673.     if ((sptr = strstr(days, str)) != NULL)
  1674.     if ((str = strtok_r(NULL, " ", &loc)) == NULL)
  1675.         return (time_t)0;
  1676.  
  1677.     /* 
  1678.      * Parse out the month, day and year. The time
  1679.      * will be parse later
  1680.      */
  1681.     if ((sptr = strstr(months, str)) != NULL) {
  1682.     new_tm.tm_mon = (int)((sptr - months) / 3);
  1683.         if ((str = strtok_r(NULL, " ", &loc)) != NULL) {
  1684.         new_tm.tm_mday = atoi(str);
  1685.         if ((jtime = strtok_r(NULL, " ", &loc)) != NULL) {
  1686.         if ((str = strtok_r(NULL, " ", &loc)) != NULL) {
  1687.             if ((new_tm.tm_year = atoi(str)) <= 0)
  1688.             new_tm.tm_year = cur_tm.tm_year;
  1689.             if (new_tm.tm_year > 1900)
  1690.             new_tm.tm_year -= 1900;
  1691.         } else {
  1692.             new_tm.tm_year = cur_tm.tm_year;
  1693.         }
  1694.         }
  1695.     }
  1696.     }
  1697.  
  1698.     /*
  1699.      * Parse the time string
  1700.      */
  1701.     if (jtime && *jtime) {
  1702.     if ((str = strtok_r(jtime, ":", &loc)) != NULL) {
  1703.         new_tm.tm_hour = atoi(str);
  1704.         if ((str = strtok_r(NULL, ":", &loc)) != NULL) {
  1705.         new_tm.tm_min = atoi(str);
  1706.             if ((str = strtok_r(NULL, ":", &loc)) != NULL) {
  1707.             new_tm.tm_sec = atoi(str);
  1708.             }
  1709.         }
  1710.     }
  1711.     }
  1712.  
  1713.     /*
  1714.      * Send back the time value. If it is negative simply set it to
  1715.      * the epoch since it is invalid anyway
  1716.      */
  1717.     if ((tval =  mktime(&new_tm)) < 0)
  1718.     tval = 0;
  1719.     return tval;
  1720. }
  1721.  
  1722.  
  1723. /**************************************************************************
  1724.  *
  1725.  * Function: getlpuid
  1726.  *
  1727.  * Description: Returns the uid of the lp account. We do this by stating
  1728.  *    the lp spooling system directory, /var/spool/lp.
  1729.  *
  1730.  * Parameters: none
  1731.  *
  1732.  * Return: UID of the lp account.
  1733.  *
  1734.  **************************************************************************/
  1735.  
  1736. static uid_t getlpuid(void)
  1737. {
  1738.     struct stat sbuf;
  1739.  
  1740.     if (stat(SL_LP_DIR, &sbuf) < 0)
  1741.     sbuf.st_uid = ~getuid();
  1742.  
  1743.     return sbuf.st_uid;
  1744. }
  1745.  
  1746.  
  1747. /**************************************************************************
  1748.  *
  1749.  * Function: read_spooler_opts_file
  1750.  *
  1751.  * Description: Reads the spoooler options file ~/SYSV_SPOOLER_FILE and
  1752.  *    sets the settings structure fields accordingly.
  1753.  *
  1754.  * Parameters:
  1755.  *    sunion (O) - settings structure union to fill
  1756.  *    format (I) - token to identify which type of structure is
  1757.  *            to be filled: spooler specific or generic.
  1758.  *
  1759.  * Return: none
  1760.  *
  1761.  **************************************************************************/
  1762.  
  1763. static void read_spooler_opts_file(SettingsUnion *sunion, int format)
  1764. {
  1765.     FILE *fptr;
  1766.     char fname[PATH_MAX], *sptr, *ptr;
  1767.     struct passwd *pw;
  1768.     char *buffer, *bptr, *loc, *title;
  1769.     struct stat sbuf;
  1770.     register int len;
  1771.  
  1772.     /*
  1773.      * Open rc file if we can
  1774.      */
  1775.     if ((pw = getpwuid(getuid())) == NULL)
  1776.     return;
  1777.     (void)sprintf(fname, "%s/%s", pw->pw_dir, SYSV_SPOOLER_FILE);
  1778.     if ((fptr = fopen(fname, "r")) == NULL)
  1779.     return;
  1780.  
  1781.     /*
  1782.      * Lock the file
  1783.      */
  1784.     (void)flock(fileno(fptr), LOCK_SH);
  1785.  
  1786.     /*
  1787.      * Stat the file to determine its size and allocate a buffer to contain
  1788.      * the entire file. The file will usually be very small so this is
  1789.      * an efficient way to deal with things.
  1790.      */
  1791.     if ((fstat(fileno(fptr), &sbuf) < 0) || !sbuf.st_size) {
  1792.         (void)flock(fileno(fptr), LOCK_UN);
  1793.     (void)fclose(fptr);
  1794.     return;
  1795.     }
  1796.     if ((buffer = (char*)malloc(sbuf.st_size + 5)) == NULL) {
  1797.         (void)flock(fileno(fptr), LOCK_UN);
  1798.     (void)fclose(fptr);
  1799.     return;
  1800.     }
  1801.  
  1802.     /*
  1803.      * Read the file, make sure it is NULL terminated, unlock and
  1804.      * close the file
  1805.      */
  1806.     (void)fread(buffer, sbuf.st_size, 1, fptr);
  1807.     buffer[sbuf.st_size] = '\0';
  1808.     if ((sptr = strrchr(buffer, '\n')) != NULL)
  1809.     *sptr = '\0';
  1810.     (void)flock(fileno(fptr), LOCK_UN);
  1811.     (void)fclose(fptr);
  1812.  
  1813.     /*
  1814.      * Parse the buffer
  1815.      */
  1816.     bptr = buffer;
  1817.     while((sptr = strtok_r(bptr, "-", &loc)) != NULL) {
  1818.     bptr = NULL;
  1819.     for (len = strlen(sptr) - 1;
  1820.         (len >= 0) && (sptr[len] == ' ' || sptr[len] == '\t'); len--)
  1821.         sptr[len] = '\0';
  1822.     switch(*sptr) {
  1823.         case SYSV_COPY_SWITCH:
  1824.         if (format == SYSV_GENERIC)
  1825.                 sunion->generic->copy = 1;
  1826.         else
  1827.                 sunion->specific->copy = 1;
  1828.         break;
  1829.         case SYSV_PRINTER_SWITCH:    /* Silently ignore this switch */
  1830.         break;
  1831.         case SYSV_MAIL_SWITCH:
  1832.         if (format == SYSV_GENERIC)
  1833.             sunion->generic->mail = 1;
  1834.         else
  1835.             sunion->specific->mail = 1;
  1836.         break;
  1837.         case SYSV_MESS_SWITCH:
  1838.         if (format == SYSV_GENERIC)
  1839.             add_opts(&sunion->generic->options, SYSV_MESS_OPTION);
  1840.         else
  1841.             sunion->specific->message = 1;
  1842.         break;
  1843.         case SYSV_NUMCOPIES_SWITCH:    /* Silently ignore this switch */
  1844.         break;
  1845.         case SYSV_SUPPRESS_SWITCH:
  1846.         if (format == SYSV_GENERIC)
  1847.             add_opts(&sunion->generic->options, SYSV_SUPPRESS_OPTION);
  1848.         else
  1849.             sunion->specific->suppress_id = 1;
  1850.         break;
  1851.         case SYSV_TITLE_SWITCH:
  1852.         title = "";
  1853.         if (sptr[1] == '"')
  1854.             title = strdup(&sptr[2]);
  1855.         else
  1856.             title = strdup(&sptr[1]);
  1857.         if ((ptr = strrchr(title, '"')) != NULL)
  1858.             *ptr = '\0';
  1859.         if (*title == '\0')
  1860.             break;
  1861.         if (format == SYSV_GENERIC)
  1862.             sunion->generic->title = title;
  1863.         else
  1864.             sunion->specific->title = title;
  1865.         break;
  1866.         default:
  1867.         break;
  1868.     }
  1869.     }
  1870.  
  1871.     /*
  1872.      * Clean up and indicate that we read a file
  1873.      */
  1874.     free((char*)buffer);
  1875. }
  1876.  
  1877.  
  1878. /**************************************************************************
  1879.  *
  1880.  * Function: write_spooler_opts_file
  1881.  *
  1882.  * Description: Writes the spooler options file ~/SYSV_SPOOLER_FILE.
  1883.  *
  1884.  * Parameters:
  1885.  *    spooler_opts (I) - options to write
  1886.  *
  1887.  * Return: 0 if successful, -1 if not.
  1888.  *
  1889.  **************************************************************************/
  1890.  
  1891. static int write_spooler_opts_file(SLSysVSpoolerOptionsStruct *spooler_opts)
  1892. {
  1893.     int fd;
  1894.     FILE *fptr;
  1895.     char fname[PATH_MAX];
  1896.     struct passwd *pw;
  1897.  
  1898.     /*
  1899.      * Open rc file if we can. We use low level IO since we want to open
  1900.      * the file read/write, no truncation and create it if it does not exist.
  1901.      * we truncate the file after we lock it.
  1902.      */
  1903.     if ((pw = getpwuid(getuid())) == NULL)
  1904.     return -1;
  1905.     (void)sprintf(fname, "%s/%s", pw->pw_dir, SYSV_SPOOLER_FILE);
  1906.     if ((fd = open(fname, O_RDWR | O_CREAT, 0666)) < 0)
  1907.     return -1;
  1908.  
  1909.     /*
  1910.      * Lock the file and then truncate it.
  1911.      */
  1912.     (void)flock(fd, LOCK_EX);
  1913.     (void)ftruncate(fd, 0);
  1914.     fptr = fdopen(fd, "r+");
  1915.  
  1916.     /*
  1917.      * Write the file. Note that we do not write the number of copies.
  1918.      * The number of copies would cause more harm than good if it were
  1919.      * placed in the rc file. Accidently setting 500 copies could have
  1920.      * interesting results for future print jobs. We also do not write
  1921.      * the printer name since this would raise confusion between the
  1922.      * system default printer and the glprc printer.
  1923.      */
  1924.     if (spooler_opts->copy)
  1925.         (void)fprintf(fptr, "-%c ", SYSV_COPY_SWITCH);
  1926.     if (spooler_opts->mail)
  1927.         (void)fprintf(fptr, "-%c ", SYSV_MAIL_SWITCH);
  1928.     if (spooler_opts->message)
  1929.         (void)fprintf(fptr, "-%c ", SYSV_MESS_SWITCH);
  1930.     if (spooler_opts->suppress_id)
  1931.         (void)fprintf(fptr, "-%c ", SYSV_SUPPRESS_SWITCH);
  1932.     if (spooler_opts->title) {
  1933.         (void)fprintf(fptr, "-%c\"%s\" ", SYSV_TITLE_SWITCH,
  1934.                         spooler_opts->title);
  1935.     }
  1936.     (void)fprintf(fptr, "\n");
  1937.  
  1938.     /*
  1939.      * Set permissions on the file,
  1940.      * unlock and close it
  1941.      */
  1942.     (void)fflush(fptr);
  1943.     (void)fchmod(fileno(fptr), 00644);
  1944.     (void)flock(fileno(fptr), LOCK_UN);
  1945.     (void)fclose(fptr);
  1946.  
  1947.     return 0;
  1948. }
  1949.  
  1950.  
  1951. /**************************************************************************
  1952.  *
  1953.  * Function: read_printer_opts_file
  1954.  *
  1955.  * Description: Reads the printer specific options settings file for the
  1956.  *    specified printer.
  1957.  *
  1958.  *    Printer specific options are stored in the directory defined by
  1959.  *    SYSV_SETTINGS_DIR/[printer name]. The file is first looked
  1960.  *    for under the username and if not found is then looked for
  1961.  *    under the name defined by SYSV_DEFAULT_SETTINGS.
  1962.  *
  1963.  * Parameters: 
  1964.  *    pname (I) - name of printer whose settings file is to be read.
  1965.  *
  1966.  * Return: Pointer to the settings option string or NULL if no settings
  1967.  *    could be read for whatever reason. It is the caller's responsibility
  1968.  *    to free the storage for the string returned by this function.
  1969.  *
  1970.  **************************************************************************/
  1971.  
  1972. static char* read_printer_opts_file(const char *pname)
  1973. {
  1974.     char *buffer;
  1975.     struct stat sbuf;
  1976.     FILE *fptr;
  1977.     char fname[PATH_MAX], *sptr;
  1978.     struct passwd *pw;
  1979.  
  1980.     /*
  1981.      * Look for the option file first by username then by default name.
  1982.      */
  1983.     pw = getpwuid(getuid());
  1984.     if (pw)
  1985.         (void)sprintf(fname, "%s/%s/%s", SYSV_SETTINGS_DIR, pname,
  1986.                         pw->pw_name);
  1987.     if (pw == NULL || (fptr = fopen(fname, "r")) == NULL) {
  1988.         (void)sprintf(fname, "%s/%s/%s", SYSV_SETTINGS_DIR, pname,
  1989.                         SYSV_DEFAULT_SETTINGS);
  1990.         if ((fptr = fopen(fname, "r")) == NULL)
  1991.             return NULL;
  1992.     }
  1993.  
  1994.     /*
  1995.      * Lock the file
  1996.      */
  1997.     (void)flock(fileno(fptr), LOCK_SH);
  1998.  
  1999.     /*
  2000.      * Stat the file to determine its size and allocate a buffer to contain
  2001.      * the entire file. The file will usually be very small so this is
  2002.      * an efficient way to deal with things.
  2003.      */
  2004.     if ((fstat(fileno(fptr), &sbuf) < 0) || !sbuf.st_size) {
  2005.         (void)flock(fileno(fptr), LOCK_UN);
  2006.     (void)fclose(fptr);
  2007.     return NULL;
  2008.     }
  2009.     if ((buffer = (char*)malloc(sbuf.st_size + 5)) == NULL) {
  2010.         (void)flock(fileno(fptr), LOCK_UN);
  2011.     (void)fclose(fptr);
  2012.     return NULL;
  2013.     }
  2014.  
  2015.     /*
  2016.      * Read the settings file, make sure it is NULL terminated and
  2017.      * close the file
  2018.      */
  2019.     (void)fread(buffer, sbuf.st_size, 1, fptr);
  2020.     buffer[sbuf.st_size] = '\0';
  2021.     (void)flock(fileno(fptr), LOCK_UN);
  2022.     (void)fclose(fptr);
  2023.  
  2024.     /*
  2025.      * Break the settings file into two separate sections by scanning for
  2026.      * \n characters and inserting \0. The settings of interest are on
  2027.      * the first line. Ignore any additional lines.
  2028.      */
  2029.     if ((sptr = strchr(buffer, '\n')) != NULL)
  2030.     *sptr = '\0';
  2031.  
  2032.     return buffer;
  2033. }
  2034.  
  2035.  
  2036. /**************************************************************************
  2037.  *
  2038.  * Function: write_printer_opts_file
  2039.  *
  2040.  * Description: Writes the printer specific options file for the
  2041.  *    specified printer.
  2042.  *
  2043.  *    Printer specific options are stored in the directory defined by
  2044.  *    SYSV_SETTINGS_DIR/[printer name]. If location is set to
  2045.  *    SL_SAVE_USER the file is written under the username. If location
  2046.  *    is SL_SAVE_DEFAULT, the file is written with the name defined
  2047.  *    by SYSV_DEFAULT_SETTINGS.
  2048.  *
  2049.  * Parameters: 
  2050.  *    pname (I) - name of printer whose options file is to be written.
  2051.  *    printer_opts (I) - printer options string
  2052.  *    location (I) - what form of options to write: local or global.
  2053.  *
  2054.  * Return: 0 if successful, -1 if not.
  2055.  *
  2056.  **************************************************************************/
  2057.  
  2058. static int write_printer_opts_file(const char *pname,
  2059.                     char *printer_opts, int location)
  2060. {
  2061.     int fd;
  2062.     FILE *fptr;
  2063.     char fname[PATH_MAX];
  2064.     struct passwd *pw;
  2065.  
  2066.     /*
  2067.      * Create the options file pathname
  2068.      */
  2069.     if (location == SL_SAVE_DEFAULT) {
  2070.     /*
  2071.      * Verify that we can do this operation then form
  2072.      * the pathname.
  2073.      */
  2074.         if ((pw = getpwuid(geteuid())) == NULL)
  2075.         return -1;
  2076.     if (strcmp(pw->pw_name, "root") && strcmp(pw->pw_name, "lp"))
  2077.         return -1;
  2078.         (void)sprintf(fname, "%s/%s/%s", SYSV_SETTINGS_DIR, pname,
  2079.                         SYSV_DEFAULT_SETTINGS);
  2080.     } else {
  2081.         if ((pw = getpwuid(getuid())) == NULL)
  2082.         return -1;
  2083.         (void)sprintf(fname, "%s/%s/%s", SYSV_SETTINGS_DIR, pname, pw->pw_name);
  2084.     }
  2085.  
  2086.     /*
  2087.      * Create the file. We use low level IO since we want to open
  2088.      * the file read/write, no truncation and create it if it does not exist.
  2089.      * we truncate the file after we lock it.
  2090.      */
  2091.     if ((fd = open(fname, O_RDWR | O_CREAT, 0666)) < 0)
  2092.     return -1;
  2093.  
  2094.     /*
  2095.      * Lock and truncate the file
  2096.      */
  2097.     (void)flock(fd, LOCK_EX);
  2098.     (void)ftruncate(fd, 0);
  2099.     fptr = fdopen(fd, "r+");
  2100.  
  2101.     /*
  2102.      * Write the printer specific options
  2103.      */
  2104.     if (printer_opts)
  2105.         (void)fprintf(fptr, "%s\n", printer_opts);
  2106.     else
  2107.         (void)fprintf(fptr, "\n");
  2108.  
  2109.     /*
  2110.      * Set permissions on the file,
  2111.      * unlock and close it
  2112.      */
  2113.     (void)fflush(fptr);
  2114.     (void)fchmod(fileno(fptr), 00644);
  2115.     (void)flock(fileno(fptr), LOCK_UN);
  2116.     (void)fclose(fptr);
  2117.  
  2118.     return 0;
  2119. }
  2120.  
  2121.  
  2122. /**************************************************************************
  2123.  *
  2124.  * Function: add_opts
  2125.  *
  2126.  * Description: Appends the specified option string to the specified 
  2127.  *    string.
  2128.  *
  2129.  * Parameters: 
  2130.  *    opt_stringp (I) - string of options
  2131.  *    new_opt (I) - option to append to string
  2132.  *
  2133.  * Return: none
  2134.  *
  2135.  **************************************************************************/
  2136.  
  2137. static void add_opts(char **opt_stringp, char *new_opt)
  2138. {
  2139.     if (*opt_stringp) {
  2140.     *opt_stringp = (char*)realloc(*opt_stringp, 
  2141.             (strlen(*opt_stringp) + strlen(new_opt) + 5) *
  2142.             sizeof(char));
  2143.         (void)strcat(*opt_stringp, " ");
  2144.     } else {
  2145.     *opt_stringp = (char*)malloc((strlen(new_opt) + 5) * sizeof(char));
  2146.     *opt_stringp[0] = '\0';
  2147.     }
  2148.     (void)strcat(*opt_stringp, new_opt);
  2149. }
  2150.  
  2151. /**************************************************************************
  2152.  *
  2153.  *  Function: sgi_get_queue
  2154.  *
  2155.  *  Description:
  2156.  *      Returns the job queue for the specified printer under the
  2157.  *      System V spooling system + SGI enhancements.  The SGI
  2158.  *      enhancements consist of some new arguments to lpstat which
  2159.  *      were implemented just for us:
  2160.  *      
  2161.  *      lpstat -lprinter gives us printer's local queue
  2162.  *      lpstat -nprinter gives us printer's remote queue
  2163.  *      lpstat -bprinter gives us both queues, with the remote queue
  2164.  *           first and a blank line in between.
  2165.  *
  2166.  *      The format of the output for all of these options is nice and
  2167.  *      easy to parse:
  2168.  *      
  2169.  *          job-id,username,size,title,timestamp
  2170.  *      
  2171.  *  Parameters:
  2172.  *    printer_info (I) - printer structure. Cannot be NULL.
  2173.  *    queue_type (I) - type of print queue to obtain (ie. local, remote
  2174.  *                or merged). The value of this parameter is
  2175.  *                ignored for local printers.
  2176.  *    queuep (O) - print queue entries.
  2177.  *    num_queuep (O) - number of entries in the queue.
  2178.  *
  2179.  *
  2180.  *  Return: 0 is execution succeeded. -1 and SLerrno is set if an execution
  2181.  *    error has occurred.
  2182.  *    
  2183.  **************************************************************************/
  2184.  
  2185. static int sgi_get_queue(const SLPrinterStruct *printer_info, int queue_type,
  2186.              SLQueueStruct *queuep[], int *num_queuep)
  2187. {
  2188.     char cmdBuf[SL_BUFSIZ], letter;
  2189.     int i, local, merge, timeout, nentries;
  2190.     SLQueueStruct *qentry, *qptr, temp_entry;
  2191.  
  2192.     /*
  2193.      * Figure out which lpstat option to use
  2194.      * 
  2195.      * The local flag is set to 1 if the first jobs we see will be
  2196.      * local, 0 otherwise.
  2197.      */
  2198.     if (!printer_info->is_networked) {
  2199.     letter = 'l';
  2200.     local = 1;
  2201.     } else {
  2202.     switch (queue_type) {
  2203.     case SL_QUEUE_LOCAL:
  2204.         letter = 'l';
  2205.         local = 1;
  2206.         break;
  2207.     case SL_QUEUE_REMOTE:
  2208.         letter = 'n';
  2209.         local = 0;
  2210.         break;
  2211.     default:
  2212.     case SL_QUEUE_MERGED:
  2213.         letter = 'b';
  2214.         local = 0;
  2215.         break;
  2216.     }
  2217.     }
  2218.  
  2219.     /*
  2220.      * Run lpstat
  2221.      */
  2222.     (void)sprintf(cmdBuf, "%s -%c%s %s", SL_CMD_LPSTAT, letter,
  2223.           printer_info->local_name, SL_SH_REDIRECT);
  2224.     if (_SLExec(NULL, cmdBuf, SL_FALSE, &timeout) != 0
  2225.     || timeout == SL_TRUE) {
  2226.     RETURN_ERROR(SL_ERR_SPOOLER_ERROR);
  2227.     }
  2228.     
  2229.     /*
  2230.      * Parse lpstat's output
  2231.      */
  2232.     merge = 0;
  2233.     for (i = 0; i < _SLspooler_nout; i++) {
  2234.     /*
  2235.      * If we see a blank line, then it's time to switch from
  2236.      * parsing remote entries to parsing local enties.  We treat
  2237.      * the first local entry specially; if we find a job in the
  2238.      * remote queue with the same user and size, we replace that
  2239.      * job with the local job on the theory that they're really
  2240.      * the same job.
  2241.      */
  2242.     if (strlen(_SLspooler_out_buf[i]) == 0) {
  2243.         merge = 1;
  2244.         continue;
  2245.     }
  2246.     if (merge) {
  2247.         merge = 0;
  2248.         local = 1;
  2249.         sgi_parse_queue(&temp_entry, _SLspooler_out_buf[i]);
  2250.         temp_entry.is_local = 1;
  2251.         for (nentries = num_sysv_queue,
  2252.          qptr = sysv_queue + num_sysv_queue - 1;
  2253.          nentries; nentries--, qptr--) {
  2254.         if (jobs_equal(printer_info, qptr, &temp_entry)) {
  2255.             _SLFreeQueueEntry(qptr);
  2256.             *qptr = temp_entry;
  2257.             break;
  2258.         }
  2259.         }
  2260.  
  2261.         if (!nentries) {
  2262.         qentry = _SLAddQueue(&sysv_queue, &num_sysv_queue);
  2263.         *qentry = temp_entry;
  2264.         }
  2265.         continue;
  2266.     }
  2267.         
  2268.     qentry = _SLAddQueue(&sysv_queue, &num_sysv_queue);
  2269.     sgi_parse_queue(qentry, _SLspooler_out_buf[i]);
  2270.     qentry->is_local = local;
  2271.     }
  2272.  
  2273.     *num_queuep = num_sysv_queue;
  2274.     *queuep = sysv_queue;
  2275.     
  2276.     return SL_NOERROR;
  2277. }
  2278.  
  2279. /**************************************************************************
  2280.  *    
  2281.  *  Function: jobs_equal
  2282.  *
  2283.  *  Description:
  2284.  *      Determine whether two job structures actually refer to the
  2285.  *      same job.
  2286.  *
  2287.  *  Parameters:
  2288.  *      printer_info (I) the printer that these jobs refer to.  Used
  2289.  *                       to find out the network type.
  2290.  *      q1 (I) one job to compare
  2291.  *      q2 (I) the other job to compare
  2292.  *
  2293.  *  Returns:
  2294.  *    1 if jobs are the same, 0 if they're not.
  2295.  *    
  2296.  **************************************************************************/
  2297.  
  2298. static int jobs_equal(const SLPrinterStruct *printer_info,
  2299.               SLQueueStruct *q1, SLQueueStruct *q2)
  2300. {
  2301.     int s1, s2;
  2302.     char *pc;
  2303.  
  2304.     /*
  2305.      * We can be pretty sure that a job in our remote queue
  2306.      * corresponds to a BSD remote job if their sequence numbers are
  2307.      * the same, mod 1000.  The mod 1000 is because BSD uses 3 digit
  2308.      * sequence numbers, while System V uses 4 digit numbers.
  2309.      * 
  2310.      * We check the user names even in this case as a sanity check.
  2311.      * BSD jobs have sequence numbers from the machines from which
  2312.      * they were submitted, so duplications are unlikely but possible.
  2313.      */
  2314.     if (printer_info->network_type
  2315.     && strcmp(printer_info->network_type, "bsd") == 0) {
  2316.     pc = strchr(q1->job_id, '-');
  2317.     if (pc) {
  2318.         s1 = atoi(pc + 1) % 1000;
  2319.         pc = strchr(q2->job_id, '-');
  2320.         if (pc) {
  2321.         s2 = atoi(pc + 1) % 1000;
  2322.         if (s1 == s2 &&
  2323.             (!q1->username || !q2->username
  2324.              || strcmp(q1->username, q2->username) == 0)) {
  2325.             return 1;
  2326.         }
  2327.         }
  2328.     }
  2329.     }
  2330.  
  2331.     /*
  2332.      * This is the old logic, the same logic you see in _SLGetQueue.
  2333.      * 
  2334.      * This logic does NOT work for BSD queues, because we (by
  2335.      * default) convert the data to PostScript.  Thus, the job sizes
  2336.      * will not be the same.
  2337.      */
  2338.     return q1->size == q2->size
  2339.     && q1->username && q2->username
  2340.         && strcmp(q1->username, q2->username) == 0;
  2341.         
  2342. }
  2343.  
  2344. /**************************************************************************
  2345.  *
  2346.  *  static char *parse(char *string, char separator)
  2347.  *
  2348.  *  Description:
  2349.  *      This is a lot like strtok, except that the separator can
  2350.  *      consist of only one character (instead of a string), and if
  2351.  *      two separators are encountered in a row, NULL is returned.
  2352.  *
  2353.  *    Note that this means that parse can return NULL for a token
  2354.  *      when a subsequent call will not return NULL.
  2355.  *
  2356.  *      This is for parsing the output of lpstat -{lnb},
  2357.  *      which can have NULL tokens in it.
  2358.  *
  2359.  *  Parameters:
  2360.  *      string     string to parse
  2361.  *      separator  char that occurs between tokens
  2362.  *
  2363.  *  Returns:
  2364.  *    next token; can be NULL
  2365.  *
  2366.  **************************************************************************/
  2367.  
  2368. static char *parse(char *string, char separator)
  2369. {
  2370.     static char *str;
  2371.     char *sep, *rv;
  2372.  
  2373.     /*
  2374.      * Reset string if it's not NULL, just like in strtok.
  2375.      */
  2376.     if (string) {
  2377.     str = string;
  2378.     }
  2379.  
  2380.     /*
  2381.      * Here's where we check for two separators in a row, and return
  2382.      * NULL if we find them.  Since we advance str past the separator
  2383.      * when we return a token, if str is still pointing at a separator
  2384.      * than there must have been two of them in a row.
  2385.      */
  2386.     if (*str == separator) {
  2387.     str++;
  2388.     return NULL;
  2389.     } else if (*str == '\0') {
  2390.     return NULL;
  2391.     }
  2392.  
  2393.     rv = str;
  2394.     sep = strchr(str, separator);
  2395.  
  2396.     if (sep) {
  2397.     *sep = '\0';
  2398.     str = sep + 1;  /* Advance str to next token for next call */
  2399.     }
  2400.     return rv;
  2401. }
  2402.  
  2403. /**************************************************************************
  2404.  *
  2405.  *  Function: sgi_parse_queue
  2406.  *
  2407.  *  Description:
  2408.  *      Parses "lpstat -l", "lpstat -n", or "lpstat -b" output into an
  2409.  *      SLQueueStruct.
  2410.  *
  2411.  *  Parameters:
  2412.  *    entry (O) - queue structure to be filled
  2413.  *    line (I) - lpstat output line to parse
  2414.  *
  2415.  **************************************************************************/
  2416.  
  2417. static void sgi_parse_queue(SLQueueStruct *entry, char *line)
  2418. {
  2419.     char *dline, *pc, *tstamp;
  2420.  
  2421.     entry->job_id = NULL;
  2422.     entry->username = NULL;
  2423.     entry->title = NULL;
  2424.     entry->size = 0;
  2425.     entry->time_stamp = 0;
  2426.     tstamp = NULL;
  2427.  
  2428.     dline = strdup(line);
  2429.     
  2430.     pc = parse(dline, ';');
  2431.     if (pc) {
  2432.     entry->job_id = strdup(pc);
  2433.     }
  2434.  
  2435.     pc = parse(NULL, ';');
  2436.     if (pc) {
  2437.     entry->username = strdup(pc);
  2438.     }
  2439.  
  2440.     pc = parse(NULL, ';');
  2441.     if (pc) {
  2442.     entry->size = atoi(pc);
  2443.     }
  2444.  
  2445.     pc = parse(NULL, ';');
  2446.     if (pc) {
  2447.     entry->title = strdup(pc);
  2448.     }
  2449.  
  2450.     pc = parse(NULL, ';');
  2451.     if (pc) {
  2452.     tstamp = pc;
  2453.     }
  2454.  
  2455.     entry->time_stamp = parse_tstamp(tstamp);
  2456.     free(dline);
  2457. }
  2458.